//
// Created by xinrong.qian on 2025/4/15.
//

#include "processor/CardProcessor.hpp"
#include <opencv2/core/mat.hpp>
#include <opencv2/opencv.hpp>
#include <vector>
#include "processor/rectangle_info.hpp"
#include "processor/QRDetector.h"

/*************************************************************************************************/
std::tuple<std::string,std::string,std::vector<double>, int, int, double, double, double>
CardProcessor::GetGrayScaleArray(const cv::Mat &image, int x, int y, int width,int height){

}

// 矫正图像，并裁剪黑边
cv::Mat
CardProcessor::correctAndCropWhiteRectangle(const cv::Mat &input) {
    cv::Mat grey;
    cv::cvtColor(input, grey, cv::COLOR_BGR2GRAY);
    cv::threshold(grey, grey, 0, 255, cv::THRESH_BINARY + cv::THRESH_OTSU);

    // 去除白色边框
    cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
    cv::morphologyEx(grey, grey, cv::MORPH_OPEN, kernel);

    kernel.release();

    // 寻找轮廓
    std::vector<std::vector<cv::Point>> contours;
    std::vector<cv::Vec4i> hierarchy;
    cv::findContours(grey, contours, hierarchy, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

    // 找到最大的轮廓
    int maxArea = 0;
    int maxIdx = -1;
    for (int i = 0; i < contours.size(); ++i) {
        int area = cv::contourArea(contours[i]);
        if (area > maxArea) {
            // 计算轮廓的边界框
            cv::Rect boundingRect = cv::boundingRect(contours[i]);
            int width = boundingRect.width;
            int height = boundingRect.height;

            // 检查宽度是否小于高度
            if (width < height) {
                maxArea = area;
                maxIdx = i;
            }

        }
    }

    // 如果找到最大轮廓
    if (maxIdx != -1) {
        // 获取轮廓的最小外接矩形
        cv::RotatedRect rotatedRect = cv::minAreaRect(contours[maxIdx]);

        // 计算旋转角度
        float angle = rotatedRect.angle;
        if (rotatedRect.size.width > rotatedRect.size.height) {
            angle -= 90.0f;
        }

        // 获取旋转矩阵
        cv::Point2f center = rotatedRect.center;
        cv::Mat rotMatrix = cv::getRotationMatrix2D(center, angle, 1.0);

        // 计算旋转后的点
        std::vector<cv::Point2f> points(4);
        cv::Point2f rectPoints[4];
        rotatedRect.points(rectPoints);
        for (int i = 0; i < 4; ++i) {
            points[i] = rectPoints[i];
        }
        std::vector<cv::Point2f> transformedPoints;
        cv::transform(points, transformedPoints, rotMatrix);

        // 计算旋转后的边界框
        cv::Rect bbox = cv::boundingRect(transformedPoints);

        // 确保边界框在图像范围内
        cv::Rect adjustedBbox = bbox & cv::Rect(0, 0, input.cols, input.rows);

        // 旋转图像
        cv::Mat rotated;
        cv::warpAffine(input, rotated, rotMatrix, input.size());

        // 裁剪出矫正后的图像
        cv::Mat cropped = rotated(adjustedBbox);

        rotMatrix.release();
        rotated.release();

        return cropped;
    }

    // 如果没有找到白色区域，返回null
    return cv::Mat();
}

// 声明扫描图像均值计算
std::vector<double>
CardProcessor::meanRoundRectangle(const cv::Mat &imgGray, int R) {
    int width = imgGray.cols;
    int height = imgGray.rows;

    std::vector<double> outVector;

    // 目标是在整个高度范围内检测每一行，
    // 对每一行中的每个点进行半径 R 的画圈，只计算圆内的区域面积，然后对每一行的结果求和。
    // 最后，继续处理下一行，直到处理完所有行。
    /*************************开始扫描**************************/
    for (int a = 0; a < height; ++a) {
        int sum_pix = 0;
        int pix_counts = 0;

        int i_min = std::max(a - R, 0);
        int i_max = std::min(a + R, height - 1);

        // 规定height方向范围
        for (int i = i_min; i <= i_max; ++i) {
            int dy = i - a;
            int dy2 = dy * dy;

            // 规定width方向范围
            int j_min = std::max(0, R - std::abs(dy));
            int j_max = std::min(width - 1, width - R + std::abs(dy));

            for (int j = j_min; j <= j_max; ++j) {
                int dx = j - R;
                int r2 = dx * dx + dy2;

                if (r2 <= R * R) {
                    sum_pix += 255 - imgGray.at<uchar>(i, j);
                    ++pix_counts;
                }
            }
        }

        if (pix_counts > 0) {
            outVector.push_back(static_cast<double>(sum_pix) / static_cast<double>(pix_counts));
        } else {
            outVector.push_back(0.0);  // 如果没有像素点在圆内，添加0.0
        }
    }
    /*************************结束扫描**************************/
    return outVector;
}

// 截取复制曲线数据
std::vector<double>
CardProcessor::crop(const std::vector<double> &data, int start, int end) {
    int size = data.size();
    if (end > size) {
        end = size;

    }
    if (start > size) {
        start = size;
        end = size;

        return std::vector<double>();
    }
    return std::vector<double>(data.begin() + start, data.begin() + end);
}

// 曲线内找最小值
cv::Point2d
CardProcessor::minPoint2d(const std::vector<double> &average) {
    int size = average.size();
    if (average.size() == 0) {
        return cv::Point2d(0, 0);
    }
    double min = average[0];
    int xmin = 0;
    for (int i(1); i < size; i++) {
        if (average[i] < min) {
            min = average[i];
            xmin = int(i);
        }
    }

    return cv::Point2d(xmin, min);
}

// 计算给定数据向量 data 在指定区间内的定积分
double
CardProcessor::getDefiniteIntegral(const std::vector<double> &data, cv::Point2d local, int hwf) {
    double out = 0;
    int start = local.x - hwf > 0 ? local.x - hwf : 0;
    int end = local.x + hwf < data.size() ? local.x + hwf : data.size();
    for (; start < end; start++) {
        out += data[start];
    }
    return out;
}

// 寻找 c t 线以及中点位置
std::tuple<int, int, int>
CardProcessor::FindPeakPoints(const std::vector<double> &grayValues) {
    if (grayValues.empty()) {
        return {-1, -1, -1};
    }

    int n = grayValues.size();
    int mid = n / 2;

    // 辅助函数：寻找指定范围内的最大值索引
    auto findMaxPeak = [](const std::vector<double> &values, int start, int end) -> int {
        if (start >= end) return -1;
        int maxIdx = start;
        double maxValue = values[start];
        for (int i = start; i < end; ++i) {
            if (values[i] > maxValue) {
                maxValue = values[i];
                maxIdx = i;
            }
        }
        return maxIdx;
    };

    int c_start = n / 5;
    int c_end = n / 2;

    int t_start = n / 2;
    int t_end = n / 5 * 4;

    // 查找前半段最大值（0到mid）
    int peak1 = findMaxPeak(grayValues, c_start, c_end);

    // 查找后半段最大值（mid到n）
    int peak2 = findMaxPeak(grayValues, t_start, t_end);

    // 检查是否存在有效波峰
    if (peak1 == -1 || peak2 == -1) {
        return {-1, -1, -1};
    }

    return {peak1, peak2, mid};
}

// 绘制折线图
void CardProcessor::drawCurve(const std::vector<double> &data) {
    if (data.empty()) {
        std::cout << "输入的数据为空，无法绘制曲线。" << std::endl;
        return;
    }

    cv::Mat image = cv::Mat::zeros(500, 800, CV_8UC3);

    int width = image.cols;
    int height = image.rows;

    // 找到数据的最大值和最小值
    double minVal, maxVal;
    cv::minMaxLoc(data, &minVal, &maxVal);

    // 计算坐标映射的比例
    double scaleX = static_cast<double>(width) / (data.size() - 1);
    double scaleY = static_cast<double>(height) / (maxVal - minVal);

    // 绘制曲线
    for (size_t i = 0; i < data.size() - 1; ++i) {
        int x1 = static_cast<int>(i * scaleX);
        int y1 = height - static_cast<int>((data[i] - minVal) * scaleY);
        int x2 = static_cast<int>((i + 1) * scaleX);
        int y2 = height - static_cast<int>((data[i + 1] - minVal) * scaleY);

        cv::line(image, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 255, 0), 2);
    }

    // 随机名称
    std::string windowName = "Curve" + std::to_string(rand());

    // 显示图像
    cv::imshow(windowName, image);
}

// 显示图像
void CardProcessor::showImage(const cv::Mat &image) {
    // 随机名称
    std::string windowName = "Image" + std::to_string(rand());

    cv::namedWindow(windowName, cv::WINDOW_NORMAL);
    cv::imshow(windowName, image);
}

// 函数用于在图像上绘制多个矩形框
void
CardProcessor::ShowMat(cv::Mat &image, const std::vector<RectangleInfo> &rectangles) {
    for (const auto &rect: rectangles) {
        cv::rectangle(image, cv::Point(rect.x1, rect.y1), cv::Point(rect.x2, rect.y2), rect.color, rect.thickness);
    }
    // 随机名称
    std::string windowName = "Mat" + std::to_string(rand());

    // 显示图像
    cv::namedWindow(windowName, cv::WINDOW_NORMAL);
    cv::imshow(windowName, image);
}

// 计算 TC 比值结果标识
std::string
CardProcessor::calculateTcResult(double tcRatio) {
    if (tcRatio == -1 || tcRatio == 0 || tcRatio == 0.01) {
        return "无效"; // 无效
    } else if (tcRatio < 0.85) {
        return "阳性"; // 阳性
    } else if (tcRatio <= 1.0) {
        return "弱阳性"; // 弱阳性
    } else {
        return "阴性"; // 阴性
    }
}

//预处理图片
cv::Mat
CardProcessor::preprocessImage(const cv::Mat& src) {
// --- 1. 灰度化 ---
    // --- 1. 灰度化（自定义权重，提高红色比重）---
    cv::Mat gray;
    cvtColor(src, gray, cv::COLOR_BGR2GRAY); // 默认使用公式: Y = 0.299R + 0.587G + 0.114B

    return gray;
}


/********************************************************/

// TcResponseInfo封装错误处理逻辑
TcResponseInfo ErrorResponseInfo(const std::string& errorMsg) {
    std::cerr << errorMsg << std::endl;
    return {errorMsg, "", {}, 0, 0, 0, 0, 0};
}

// TcResponseInfo封装成功返回函数
TcResponseInfo SuccessResponseInfo(const std::string& successMsg, const std::string& tcResult,
                                   const std::vector<double>& grayValues, int pc, int pt,
                                   double cValue, double tValue, double tcRatio) {
    return {successMsg, tcResult, grayValues, pc, pt, cValue, tValue, tcRatio};
}

/**
 * 请求返回函数
 *
 * @param image
 * @param x
 * @param y
 * @param width
 * @param height
 * @return TcResponseInfo
 */
TcResponseInfo
CardProcessor::GetTcResponseInfo(const cv::Mat &image, int x, int y, int width, int height) {
    // 确保图像非空
    if (image.empty()){
        std::cerr << "The input image is empty" << std::endl;
        return ErrorResponseInfo("The input image is empty");
    }

    std::vector<CTLineResult> resultsArr; // 存储多个CTLineResult

    // 统一异常捕获处理
    try {
        // 利用二维码定位算法
        QRDetector detector;
        // 设置参数
        detector.setRoiParameters(1.15, 0.1, 0.95);

        // 3. 执行检测
        if (!detector.detect(image)){
            std::cerr << "二维码扫描失败!" << std::endl;
            return ErrorResponseInfo("二维码扫描失败!");
        }

        // 二维码扫描成功
        // 获取二维码数据
        const auto& corners = detector.getAllQrCorners();
        const auto& rois = detector.getExtractedROIs();

        for (size_t i = 0; i < corners.size();  ++i) {
            std::cout << "QR: " << (i + 1) << "  ,  size: " << detector.getQrSideLengths()[i]  << std::endl;

            cv::Mat roi = rois[i];

            if (roi.empty()){
                std::cerr << "ROI: " << (i + 1) << " is empty" << std::endl;
                continue;
            }

            // 进行TC检测计算 - 传入检测区域图片
            CTLineResult result = CalculateTc(roi);

            resultsArr.push_back(result); // 将结果添加到数组中，当前只返回第一个处理结果

//            /***********************UI窗口 release删除****************************/
//            // 显示marked QR
//            cv::Mat marked = detector.getMarkedImage();
//            cv::imshow("Marked QR Code", marked);
//
//            //描绘CT位置
//            int x1 = 0;
//            int x2 = roi.rows;
//
//            RectangleInfo cLine{
//                    x1,
//                    result.pc,
//                    x2,
//                    result.pc,
//                    cv::Scalar(0, 0, 255), // 红色
//                    1
//            };
//
//            RectangleInfo tLine{
//                    x1,
//                    result.pt,
//                    x2,
//                    result.pt,
//                    cv::Scalar(0, 255, 0), // 绿色
//                    1
//            };
//
//            std::vector<RectangleInfo> rectangles = {cLine, tLine};
//            ShowMat(roi, rectangles);
//
//            drawCurve(result.grayValues); // 折线
//            /***********************UI窗口 release删除****************************/

        }

//        /***********************UI窗口 release删除****************************/
//        cv::waitKey(0);
//        /***********************UI窗口 release删除****************************/

        // 所有检测完成，返回第一个处理结果
        CTLineResult result = resultsArr[0];

        return SuccessResponseInfo("Success",
                                   result.tcResult,
                                   result.grayValues,
                                   result.pc,
                                   result.pt,
                                   result.cValue,
                                   result.tValue,
                                   result.tcRatio); // 调用TC计算函数

    } catch (const std::exception &e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        return ErrorResponseInfo("Internal exception");
    }

}

/**
 * 计算TC
 *
 * @param image
 * @return CTLineResult
 */
CTLineResult
CardProcessor::CalculateTc(const cv::Mat &image) {
    CTLineResult result;

    if (image.empty()) {
        throw std::runtime_error("The input image is empty");
    }

    // 预处理后的mat
    cv::Mat channelBitmap = preprocessImage(image);
    // 图片尺寸大小
    std::cout << "Image size: " << channelBitmap.rows << " x " << channelBitmap.cols << std::endl;

    std::vector<double> greyArray = meanRoundRectangle(channelBitmap, 3);

    auto [cPosition, tPosition, mPosition] = FindPeakPoints(greyArray);
    result.pc = cPosition;
    result.pt = tPosition;

    if (result.pc == -1 || result.pt == -1) {
        throw std::runtime_error("Image detection area C T line not found, please check the detection card");
    }

    std::cout << "pc: " << result.pc << std::endl;
    std::cout << "pt: " << result.pt << std::endl;
    std::cout << "mid: " << mPosition << std::endl;

    std::vector<double> ctCurve = crop(greyArray, result.pc, result.pt);
    cv::Point2d ctMidMinPoint = minPoint2d(ctCurve);

    result.grayValues.resize(greyArray.size(), 0);
    for (size_t i = 0; i < greyArray.size(); ++i) {
        result.grayValues[i] = std::max(0.0, greyArray[i] - ctMidMinPoint.y);
    }

    int hwf = 5; // 半峰宽
    double limit = 0.5; // 限值

    double minToMax_C = std::abs(result.grayValues[result.pc] - ctMidMinPoint.y);
    double minToMax_T = std::abs(result.grayValues[result.pt] - ctMidMinPoint.y);

    result.cValue = (minToMax_C > limit) ? getDefiniteIntegral(result.grayValues,
                                                               cv::Point2d(result.pc, result.grayValues[result.pc]),
                                                               hwf) : 0;
    result.tValue = (minToMax_T > limit) ? getDefiniteIntegral(result.grayValues,
                                                               cv::Point2d(result.pt, result.grayValues[result.pt]),
                                                               hwf) : 0;

    if (result.cValue == 0 && result.tValue == 0) { // 1.无CT线
        result.tcRatio = -1;
        std::fill(result.grayValues.begin(), result.grayValues.end(), 0);
    } else if (result.cValue == 0) { // 2.无C线
        result.tcRatio = -1;
        std::fill(result.grayValues.begin(), result.grayValues.begin() + ctMidMinPoint.x, 0);
    } else if (result.tValue == 0) { // 3.无T线
        result.tcRatio = 0.01;
        std::fill(result.grayValues.begin() + ctMidMinPoint.x, result.grayValues.end(), 0);
    } else { // 4.正常计算
        result.tcRatio = std::round((result.tValue / result.cValue) * 100.0) / 100.0; // 计算 TC 比值 （保留两位小数）
    }

    // 阴阳性判别
    result.tcResult = calculateTcResult(result.tcRatio);

    std::cout << "c: " << result.cValue << std::endl;
    std::cout << "t: " << result.tValue << std::endl;
    std::cout << "tcRatio: " << result.tcRatio << std::endl;
    std::cout << "tcResult: " << result.tcResult << std::endl;

    channelBitmap.release();
    return result;
}